/**
 * 浮点数           minimum size
 *   float           4 bytes
 *   double          8 bytes
 *   long double     8 bytes
 * 
 * 最佳实践
 * 始终确保文字的类型与它们被分配或用于初始化的变量的类型相匹配。否则将导致不必要的转换，并可能导致精度损失。
 * 
 * 当输出浮点数时，std::cout 的默认精度为 6——也就是说，它假设所有浮点变量仅对 6 位有效（浮点数的最小精度），因此它将截断之后的任何内容。
 * 
 * 最佳实践
 * 除非空间非常宝贵，否则优先选择双倍浮动，因为浮动缺乏精度通常会导致不准确
 * 
 * 舍入误差使浮点比较变得棘手
 * 由于二进制（数据的存储方式）和十进制（我们的思维方式）之间没有明显的差异，浮点数使用起来很棘手。
 * 考虑分数 1/10。在十进制中，这很容易表示为 0.1，并且我们习惯于将 0.1 视为具有 1 个有效数字的易于表示的数字。
 * 然而，在二进制中，十进制值 0.1 由无限序列表示：0.00011001100110011… 因此，当我们将 0.1 分配给浮点数时，我们会遇到精度问题。
 * 
 * 
 * 当数字无法精确存储时，就会出现舍入错误。即使是简单的数字（例如 0.1）也可能发生这种情况。
 * 因此，舍入误差可能而且确实一直会发生。舍入误差并不是例外——它们是规则。永远不要假设你的浮点数是精确的。
 * 此规则的推论是：谨慎使用浮点数表示金融或货币数据。
 * 
 * 
 * NaN 和 Inf
 * 浮点数有两种特殊类别。第一个是Inf，代表无穷大。Inf 可以是正值，也可以是负值。
 * 第二个是NaN，它代表“不是数字”。有几种不同类型的 NaN（我们不会在这里讨论）。
 * 仅当编译器对浮点数使用特定格式 (IEEE 754) 时，NaN 和 Inf 才可用。如果使用其他格式，以下代码会产生未定义的行为。
 * 
 * 最佳实践
 * 完全避免除以 0.0，即使您的编译器支持它。
 * 
 * 
 * 总而言之，关于浮点数，您应该记住两件事：
 *   浮点数对于存储非常大或非常小的数字非常有用，包括那些带有小数部分的数字。
 *   浮点数通常具有较小的舍入误差，即使该数字的有效位数少于精度。很多时候，这些数据会被忽视，因为它们太小，而且数字在输出时被截断。然而，浮点数的比较可能不会给出预期的结果。对这些值执行数学运算将导致舍入误差变大。
 * 
 */

#include <iomanip> // for std::setprecision()
#include <iostream>

int main() {
    float fValue;
    double dValue;
    long double ldValue;

    int x{5};      // 5 means integer
    double y{5.0}; // 5.0 is a floating point literal (no suffix means double type by default)
    float z{5.0f}; // 5.0 is a floating point literal, f suffix means float type

    std::cout << 5.0 << '\n';
	std::cout << 6.7f << '\n';
	std::cout << 9876543.21 << '\n';

    std::cout << 9.87654321f << '\n';
    std::cout << 987.654321f << '\n';
    std::cout << 987654.321f << '\n';
    std::cout << 9876543.21f << '\n';
    std::cout << 0.0000987654321f << '\n';


    double d{0.1};
    std::cout << d << '\n'; // use default cout precision of 6
    std::cout << std::setprecision(17);
    std::cout << d << '\n';


    double d1{ 1.0 };
    std::cout << d1 << '\n';

    double d2{ 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 }; // should equal 1.0
    std::cout << d2 << '\n';


    double zero {0.0};
    double posinf { 5.0 / zero }; // positive infinity
    std::cout << posinf << '\n';

    double neginf { -5.0 / zero }; // negative infinity
    std::cout << neginf << '\n';

    double nan { zero / zero }; // not a number (mathematically invalid)
    std::cout << nan << '\n';
    
    return 0;
}